package com.wzw.springboot.principle.use.security.manage;

import com.wzw.springboot.principle.use.security.entity.RoleEntity;
import com.wzw.springboot.principle.use.security.entity.UserEntity;
import com.wzw.springboot.principle.use.security.entity.UserRoleEntity;
import com.wzw.springboot.principle.use.security.enums.UserStatusEnum;
import com.wzw.springboot.principle.use.security.infrastructure.model.SecurityAuthority;
import com.wzw.springboot.principle.use.security.infrastructure.model.SecurityUser;
import com.wzw.springboot.principle.use.security.repository.*;
import com.wzw.springboot.principle.use.thirdparty.loginauth.ThirdPartyUser;
import lombok.RequiredArgsConstructor;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import java.util.*;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 权限聚合
 *
 * @author Wangzhiwen
 */
@Component
@RequiredArgsConstructor
public class RbacManager {

    private final UserRepository userRepository;

    private final UserRoleRepository userRoleRepository;

    private final RoleRepository roleRepository;

    private final MenuRepository menuRepository;

    private final RoleMenuRepository roleMenuRepository;

    private final JdbcTemplate jdbcTemplate;

    public SecurityUser getSecurityUserByAccount(String account) {
        UserEntity userEntity = getUserByAccount(account);
        return toSecurityUser(userEntity);
    }

    public SecurityUser getSecurityUserByMobile(String mobile) {
        UserEntity userEntity = getUserByMobile(mobile);
        return toSecurityUser(userEntity);
    }

    public SecurityUser getSecurityUserByThirdPartyUser(ThirdPartyUser thirdPartyUser) {
        return new SecurityUser();
    }

    public SecurityUser toSecurityUser(UserEntity userEntity) {
        SecurityUser securityUser = new SecurityUser();
        securityUser.setId(userEntity.getId());
        securityUser.setAccount(userEntity.getAccount());
        securityUser.setMobile(userEntity.getMobile());
        securityUser.setPassword(userEntity.getPassword());
        securityUser.setUsername(userEntity.getUsername());
        securityUser.setEmail(userEntity.getEmail());
        UserStatusEnum statusEnum = UserStatusEnum.valueOf(userEntity.getStatus().toUpperCase(Locale.ROOT));
        switch (statusEnum) {
            case LOCKED:
                securityUser.setAccountNonLocked(false);
                break;
            case DISABLED:
                securityUser.setEnabled(false);
                break;
            case ACCOUNT_EXPIRED:
                securityUser.setAccountNonExpired(false);
                break;
            default:
                // ignored
        }
        // 角色与权限标识
        List<RoleEntity> roles = this.getUserRoles(userEntity.getId());
        if (CollectionUtils.isEmpty(roles)) {
            securityUser.setAuthorities(Collections.emptyList());
        } else {
            List<GrantedAuthority> authorities = roles.stream().map((Function<RoleEntity, GrantedAuthority>) roleEntity -> new SecurityAuthority(roleEntity.getCode(), roleEntity.getCode())).collect(Collectors.toList());
            securityUser.setAuthorities(authorities);
        }
        return securityUser;
    }

    public UserEntity getUserByAccount(String account) {
        if (ObjectUtils.isEmpty(account)) {
            throw new UsernameNotFoundException("账号[" + account + "]为空");
        }
        return Optional.ofNullable(userRepository.findByAccount(account)).orElseThrow((Supplier<AuthenticationException>) () -> new UsernameNotFoundException("账号[" + account + "]不存在"));
    }

    public UserEntity getUserByMobile(String mobile) {
        if (ObjectUtils.isEmpty(mobile)) {
            throw new UsernameNotFoundException("手机号[" + mobile + "]为空");
        }
        return Optional.ofNullable(userRepository.findByMobile(mobile)).orElseThrow(() -> new UsernameNotFoundException("手机号[" + mobile + "]不存在"));
    }

    public List<RoleEntity> getUserRoles(Long userId) {
        List<UserRoleEntity> roleEntities = userRoleRepository.findByUserId(userId);
        Set<Long> roleIds = roleEntities.stream().map(UserRoleEntity::getRoleId).collect(Collectors.toSet());
        return roleRepository.findAllById(roleIds);
    }

    public RoleEntity getUserRole(Long userId, String code) {
        // jdbcTemplate.query(RbacSql.FIND_USER_ROLE, )
        return null;
    }

    public interface RbacSql {
        String FIND_USER_ROLE = "SELECT * FROM ROLE LEFT JOIN";
    }
}
